# _*_ coding: utf-8 _*_
import requests
import json
import os
import time
import logging
import threading
from datetime import datetime
from utils import synergism, zytoken, zymysql, userface

# 配置参数
MAX_RETRY_TIMES = 3  # 最大重试次数
DELAY_SECONDS = 7  # 默认延迟时间（秒）
PORT = 4370
PASSWORD = ""  # 用户密码
PRIVILEGE = 0  # 用户权限：0为普通用户
ENABLED = 1  # 用户启用标志：1为启用

# 全局锁用于线程安全
device_lock = threading.Lock()
db_lock = threading.Lock()


# 设置日志配置
def setup_logging():
    current_dir = os.path.dirname(os.path.abspath(__file__))
    target_dir = os.path.join(os.path.dirname(current_dir), "logs")
    os.makedirs(target_dir, exist_ok=True)
    log_filename = os.path.join(target_dir, "attendance_record.log")
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler(log_filename),
            logging.StreamHandler()
        ]
    )


def stitch_data(summaryid):
    """获取表单数据并处理附件"""
    url = 'http://192.168.0.13:4865/seeyon/rest/form/getformdata/' + str(summaryid)
    ZYtoken = zytoken.getzytoken()
    header = {"token": ZYtoken}
    try:
        req = requests.get(url, headers=header, timeout=30)
        result = req.json()  # 获得致远表单数据
        zhu = json.loads(result['DataJson'])[0]  # 主表字段
        print(zhu)
        devlistz = []
        devlist = tuple(zhu['field0097'].split(','))
        for dev in devlist:
            with db_lock:
                devname = \
                    zymysql.seeyon_query("Select ctp_enum_item.showvalue from ctp_enum_item  where id=" + str(dev))[0][0]
            devlistz.append(devname)
        print(devlistz)
        ctpreference = zymysql.seeyon_query(
            "SELECT FILE_URL,FILENAME from ctp_attachment WHERE SUB_REFERENCE=" + str(zhu['field0098']))
        ctp_file_ID = ctpreference[0][0]  # 附件ID
        fileName = ctpreference[0][1]  # 文件名称
        dwEnrollNumber = zhu['field0058']  # 考勤号码

        token = zytoken.shen_header()['token']

        ctpurl = f'http://192.168.0.13:4865/seeyon/rest/attachment/file/{ctp_file_ID}?fileName={fileName}&token={token}'
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
            "Accept": "text/plain, */*; q=0.01",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Referer": "http://192.168.0.13:4865/seeyon/main.do",
        }
        # 发送 GET 请求
        response = requests.get(ctpurl, headers=headers)
        # 定义目标目录和路径
        current_dir = os.path.dirname(os.path.abspath(__file__))
        target_dir = os.path.join(os.path.dirname(current_dir), "upload")  # 子目录名称
        os.makedirs(target_dir, exist_ok=True)  # exist_ok=True 防止目录已存在时报错
        target_path = os.path.join(target_dir, fileName)  # 自动处理路径分隔符

        # 保存文件到指定目录
        with open(target_path, 'wb') as f:
            f.write(response.content)
        # 输出带完整路径的信息
        absolute_path = os.path.abspath(target_path)
        new_name = f"verify_biophoto_9_{dwEnrollNumber}.jpg"  # 新文件名
        renamefile = userface.rename_file(absolute_path, new_name)

        logging.info(f"成功获取表单数据: {zhu}---{devlistz}---{renamefile}")
        return zhu, devlistz, renamefile

    except Exception as e:
        logging.error(f"获取表单数据失败, summaryid: {summaryid}, 错误: {str(e)}")
        raise  # 重新抛出异常，以便在外层捕获并记录


def perform_operation_with_retry(operation, operation_name, max_retries=MAX_RETRY_TIMES, **kwargs):
    """执行操作并自动重试"""
    for attempt in range(1, max_retries + 1):
        try:
            result = operation(**kwargs)
            if result:
                return result
            logging.warning(f"{operation_name}失败，尝试 {attempt}/{max_retries}")
        except Exception as e:
            logging.warning(f"{operation_name}异常: {str(e)}，尝试 {attempt}/{max_retries}")

        if attempt < max_retries:
            time.sleep(DELAY_SECONDS * attempt)  # 指数退避
    raise


def process_device_safely(ip, machine_num, enroll_num, name, renamefile):
    """线程安全的设备处理"""
    try:
        with device_lock:
            # 连接设备
            perform_operation_with_retry(
                userface.connect_to_device, "连接设备",
                ip=ip, port=PORT
            )

            # 创建用户
            perform_operation_with_retry(
                userface.create_user, "创建用户",
                dwMachineNumber=machine_num, dwEnrollNumber=enroll_num,
                Name=name, Password=PASSWORD, Privilege=PRIVILEGE, Enabled=ENABLED
            )

            # 上传人脸
            perform_operation_with_retry(
                userface.send_user_face_photo, "上传人脸",
                machine_number=machine_num, file_name=renamefile
            )

            print(f"设备 {ip} 操作成功完成")
            return True

    except Exception as e:
        print(f"设备 {ip} 操作失败: {str(e)}")
        return False


def insert_user_safely(zhu):
    """线程安全的用户插入"""
    name = zhu['field0007']
    enroll_num = zhu['field0058']
    try:
        with db_lock:
            # 检查用户是否存在
            check_sql = "SELECT COUNT(*) FROM userinfo WHERE Badgenumber = %s"
            existing_count = zymysql.zkteco_query(check_sql, (enroll_num,))[0][0]

            if existing_count == 0:
                insert_sql = """
                    INSERT INTO userinfo (USERID, Badgenumber, SSN, Name, FSelected) 
                    VALUES (%s, %s, %s, %s, %s)
                """
                params = (enroll_num, enroll_num, '', name, 0)
                zymysql.zkteco_execute(insert_sql, params)
                logging.info(f"成功插入新用户: {enroll_num} - {name}")
            else:
                logging.info(f"用户已存在: {enroll_num} - {name}")

            return True

    except Exception as e:
        logging.error(f"数据库操作失败: {str(e)}")
        return False


def process_summary(summaryid):
    """处理单个summaryid的完整流程"""
    try:
        # 获取数据
        zhu, devlistz, renamefile = perform_operation_with_retry(
            stitch_data, "获取表单数据", summaryid=summaryid)

        # 处理设备
        name = zhu['field0007']
        enroll_num = zhu['field0058']
        for entry in devlistz:
            try:
                ip, machine_num = entry.split(':')
                logging.info(f"开始处理设备 {ip} (机器号:{machine_num})")
                if not process_device_safely(ip, machine_num, enroll_num, name, renamefile):
                    logging.error(f"设备 {ip} 处理失败")
                    # 可以继续尝试下一个设备，不立即终止
            except ValueError as e:
                logging.error(f"设备条目格式错误: {entry}, 错误: {str(e)}")
            except Exception as e:
                logging.error(f"处理设备 {entry} 时发生意外错误: {str(e)}")
            time.sleep(DELAY_SECONDS)  # 设备间间隔

        # 更新数据库
        if not insert_user_safely(zhu):
            logging.error("数据库更新失败")
            return False

        logging.info(f"成功处理 summaryid: {summaryid}")
        return True

    except Exception as e:
        logging.error(f"处理 summaryid {summaryid} 失败: {str(e)}")
        return False


def start(summaryid):
    """启动处理流程"""
    setup_logging()
    logging.info(f"开始处理 summaryid: {summaryid}")

    try:
        process_summary(summaryid)
    except Exception as e:
        logging.error(f"处理 summaryid {summaryid} 时发生未捕获的异常: {str(e)}")
    finally:
        logging.info(f"完成 summaryid: {summaryid} 的处理")


def get_attendance_records_by_phone(tel, start_ts=None, end_ts=None):
    """
    根据手机号和时间范围查询打卡记录
    :param tel: 手机号（必填）
    :param start_ts: 开始时间戳（秒级）
    :param end_ts: 结束时间戳（秒级）
    :return: 查询结果列表
    """
    base_sql = """
               SELECT
                   a.member_name,
                   a.member_id,
                   a.tel,
                   b.app_user_id,
                   FROM_UNIXTIME(b.sign_datetime / 1000, '%%Y-%%m-%%d %%H:%%i:%%S') AS create_date
               FROM
                   `att_member` a
                       LEFT JOIN att_historyrecord b ON a.member_id = b.member_id
               WHERE
                   a.tel = %s 
               """
    params = [tel]

    if start_ts is not None and end_ts is not None:
        base_sql += " AND b.sign_datetime >= %s AND b.sign_datetime <= %s"
        params.extend([start_ts, end_ts])

    base_sql += " ORDER BY create_date DESC"

    try:
        result = zymysql.zkteco_query(base_sql, tuple(params))
        columns = ['member_name', 'member_id', 'tel', 'app_user_id', 'create_date']
        return [dict(zip(columns, row)) for row in result] if result else []
    except Exception as e:
        raise RuntimeError(f"数据库查询失败: {str(e)}")

if __name__ == '__main__':
    # 示例调用
    summaryid = "-9065446730617896711"
    start(summaryid)